// phalanx complex.hpp.cu header file

// Copyright (c) 2011 - 2011 Kohei Takahashi (Flast).
// Distributed under the MIT license. for more detail see COPYING.

// Redefinition std::complex (C++0x's)

#ifndef IG_PHALANX_MATH_COMPLEX_HPP_CU_ONCE_
#define IG_PHALANX_MATH_COMPLEX_HPP_CU_ONCE_

#include <phalanx/config.hpp.cu>

#include <device_functions.h>

#include <phalanx/math/complex/complex_fwd.hpp.cu>
#include <phalanx/math/complex/operators.hpp.cu>
#include <phalanx/math/complex/functions.hpp.cu>

#include <phalanx/utility/enable_if.hpp.cu>

#include <phalanx/type_traits/is_float.hpp.cu>

namespace phalanx
{

namespace math
{

// XXX: If T is not floating point type, complex< T > is ill-formed.
template < typename T >
struct complex
{
    typedef typename enable_if< is_float< T >, T >::type value_type;

    value_type Re_, Im_;

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex( const value_type &re = value_type(),
             const value_type &im = value_type() )
      : Re_( re ), Im_( im ) {}

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex( const complex &comp )
      : Re_( comp.real() ), Im_( comp.imag() ) {}

    template < typename X >
    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex( const complex< X > &comp )
      : Re_( comp.real() ), Im_( comp.imag() ) {}

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    value_type
    real( void ) const
    { return Re_; }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    void
    real( value_type re_ )
    { Re_ = re_; }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    value_type
    imag( void ) const
    { return Im_; }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    void
    imag( value_type im_ )
    { Im_ = im_; }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator=( const value_type &x_ )
    {
        Re_ = x_;
        Im_ = value_type();
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator+=( const value_type &x_ )
    {
        Re_ += x_;
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator-=( const value_type &x_ )
    {
        Re_ -= x_;
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator*=( const value_type &x_ )
    {
        Re_ *= x_;
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator/=( const value_type &x_ )
    {
        Re_ /= x_;
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator=( const complex &x_ )
    {
        Re_ = x_.Re_;
        Im_ = x_.Im_;
        return *this;
    }

    template < typename X >
    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator=( const complex< X > &x_ )
    {
        Re_ = x_.Re_;
        Im_ = x_.Im_;
        return *this;
    }

    template < typename X >
    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator+=( const complex< X > &x_ )
    {
        Re_ += x_.Re_;
        Im_ += x_.Im_;
        return *this;
    }

    template < typename X >
    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator-=( const complex< X > &x_ )
    {
        Re_ -= x_.Re_;
        Im_ -= x_.Im_;
        return *this;
    }

    template < typename X >
    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator*=( const complex< X > &x_ )
    {
        Re_ *= x_.Re_;
        Im_ *= x_.Im_;
        return *this;
    }

    template < typename X >
    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator/=( const complex< X > &x_ )
    {
        Re_ /= x_.Re_;
        Im_ /= x_.Im_;
        return *this;
    }
};

template <>
struct complex< float >
{
    typedef float value_type;

    float Re_, Im_;

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex( float re = 0.0f, float im = 0.0f )
      : Re_( re ), Im_( im ) {}

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    explicit
    complex( const complex &comp )
      : Re_( comp.real() ), Im_( comp.imag() ) {}

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    float
    real( void ) const
    { return Re_; }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    void
    real( float re_ )
    { Re_ = re_; }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    float
    imag( void ) const
    { return Im_; }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    void
    imag( float im_ )
    { Im_ = im_; }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator=( const float x_ )
    {
        Re_ = x_;
        Im_ = 0.0f;
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator+=( const float x_ )
    {
        Re_ += x_;
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator-=( const float x_ )
    {
        Re_ -= x_;
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator*=( const float x_ )
    {
        Re_ *= x_;
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator/=( const float x_ )
    {
        Re_ /= x_;
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator=( const complex &x_ )
    {
        Re_ = x_.Re_;
        Im_ = x_.Im_;
        return *this;
    }

    template < typename X >
    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator=( const complex< X > &x_ )
    {
        Re_ = x_.Re_;
        Im_ = x_.Im_;
        return *this;
    }

    template < typename X >
    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator+=( const complex< X > &x_ )
    {
        Re_ += x_.Re_;
        Im_ += x_.Im_;
        return *this;
    }

    template < typename X >
    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator-=( const complex< X > &x_ )
    {
        Re_ -= x_.Re_;
        Im_ -= x_.Im_;
        return *this;
    }

    template < typename X >
    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator*=( const complex< X > &x_ )
    {
        Re_ *= x_.Re_;
        Im_ *= x_.Im_;
        return *this;
    }

    template < typename X >
    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator/=( const complex< X > &x_ )
    {
        Re_ /= x_.Re_;
        Im_ /= x_.Im_;
        return *this;
    }
};

template <>
struct complex< double >
{
    typedef double value_type;

    double Re_, Im_;

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex( double re = 0.0, double im = 0.0 )
      : Re_( re ), Im_( im ) {}

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex( const complex &comp )
      : Re_( comp.real() ), Im_( comp.imag() ) {}

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    double
    real( void ) const
    { return Re_; }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    void
    real( double re_ )
    { Re_ = re_; }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    double
    imag( void ) const
    { return Im_; }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    void
    imag( double im_ )
    { Im_ = im_; }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator=( const double x_ )
    {
        Re_ = x_;
        Im_ = 0.0f;
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator+=( const double x_ )
    {
        Re_ += x_;
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator-=( const double x_ )
    {
        Re_ -= x_;
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator*=( const double x_ )
    {
        Re_ *= x_;
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator/=( const double x_ )
    {
        Re_ /= x_;
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator=( const complex &x_ )
    {
        Re_ = x_.Re_;
        Im_ = x_.Im_;
        return *this;
    }

    template < typename X >
    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator=( const complex< X > &x_ )
    {
        Re_ = x_.Re_;
        Im_ = x_.Im_;
        return *this;
    }

    template < typename X >
    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator+=( const complex< X > &x_ )
    {
        Re_ += x_.Re_;
        Im_ += x_.Im_;
        return *this;
    }

    template < typename X >
    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator-=( const complex< X > &x_ )
    {
        Re_ -= x_.Re_;
        Im_ -= x_.Im_;
        return *this;
    }

    template < typename X >
    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator*=( const complex< X > &x_ )
    {
        Re_ *= x_.Re_;
        Im_ *= x_.Im_;
        return *this;
    }

    template < typename X >
    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    complex &
    operator/=( const complex< X > &x_ )
    {
        Re_ /= x_.Re_;
        Im_ /= x_.Im_;
        return *this;
    }
};

} // namespace math

} // namespace phalanx

#endif // IG_PHALANX_MATH_COMPLEX_HPP_CU_ONCE_

